package cate.game.role.bag.spice;

import cate.common.table.d.GDObj;
import cate.common.table.item.spice.row.SpiceBaseRow;
import cate.common.table.item.spice.row.SpicePosRow;
import cate.common.util.GameResult;
import cate.game.attr.PowerAttrPart;
import cate.game.attr.SpicesPowerAttrPart;
import cate.game.client.msg.MergeMsgSender;
import cate.game.event.hero.HeroPowerChangeEvent;
import cate.game.play.support.PlayBuildContext;
import cate.game.res.RewardShow;
import cate.game.role.Role;
import cate.game.role.RoleDependent;
import cate.game.role.bag.hero.Hero;
import cate.game.train.spice.msg.SpiceUpdateResp;
import com.fasterxml.jackson.annotation.JsonIgnore;
import cp.solution.pattern.ICopiable;
import easy.java.dev.note.NoteClass;
import easy.java.dev.note.NoteField;
import org.apache.commons.lang3.SerializationUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.annotation.Transient;

import java.util.*;

@NoteClass(value = "英雄穿戴的星格")
public class SpicesOn extends RoleDependent implements ICopiable<SpicesOn> {
    @JsonIgnore
    @Transient
    public transient Hero owner;

    @NoteField(value = "英雄身上的星格", detail = "Map<部位:Byte, 星格uid>")
    public Map<Byte, String> spiceMap;
    @NoteField(value = "星格数据", detail = "只有观察和上榜的时候才会赋值")
    public Map<String, SpiceVO> spiceData;

    public void initialize(Hero owner, Role role){
        super.initialize(role);
        this.owner = owner;
        if(spiceMap == null){
            spiceMap = new HashMap<>();
        }
    }

    public void gainSpiceData() {
        if (role == null) {
            return;
        }
        spiceData = new HashMap<>();
        if (!spiceMap.isEmpty()) {
            for (String spiceUid : spiceMap.values()) {
                Spice spice = role.getBag().spice.getItem(spiceUid);
                if (spice != null) {
                    SpiceVO vo = new SpiceVO();
                    vo.tid = spice.tid;
                    vo.level = spice.level;
                    vo.broken = spice.broken;
                    spiceData.put(spiceUid, vo);
                }
            }
        }
    }

    public void clearSpiceData() {
        spiceData = null;
    }

    public PowerAttrPart getPowerAttrPart(PlayBuildContext ctx) {
        return new SpicesPowerAttrPart(ctx, this);
    }

    /** 香料栏位检测 */
    private GameResult<Void> preCheckOn(PlayBuildContext ctx, byte pos, Spice e){
        GameResult<Void> r = new GameResult<>();
        SpicePosRow posRow = ctx.spiceExcel().pos.get((int)pos);
        if (posRow == null) {
            return r.fail("所选栏位不存在");
        }
        int heroStar = owner.getTpl(ctx).star;
        if (heroStar < posRow.star) {
            return r.fail("英雄星级达到{}星时解锁栏位", posRow.star);
        }
        SpiceBaseRow baseRow = e.getTpl(role.toPlayBuildContext());
        if (baseRow == null) {
            return r.fail("穿戴的星格有误");
        }
        if(!baseRow.posList.contains(pos)){
            return r.fail("穿戴栏位有误");
        }
        return r.success();
    }

    @JsonIgnore
    public List<Integer> getSkills(PlayBuildContext ctx){
        List<Integer> skills = new ArrayList<>();
        if(owner == null || owner.getTpl(ctx) == null){
            return skills;
        }
        return skills;
    }

    @Override
    public SpicesOn copy() {
        SpicesOn cp = new SpicesOn();
        cp.spiceMap = SerializationUtils.clone((HashMap<Byte, String>)this.spiceMap);
        cp.initialize(this.owner, this.role);
        return cp;
    }

    public RewardShow offAll(Role role, Hero hero, MergeMsgSender sender, boolean updatePower) {
        RewardShow rewardShow = new RewardShow();
        for (String uid : spiceMap.values()) {
            Spice spice = role.getBag().spice.getItem(uid);
            if (spice != null) {
                spice.onHeroUid = null;
                role.sendNow(new SpiceUpdateResp(spice));
                rewardShow.addInsRwd(GDObj.Type.SPICE, uid);
            }
        }
        spiceMap.clear();
        if (updatePower) {
            role.getBase().updatePower();
            publishEvent(role, new HeroPowerChangeEvent(hero.getRole(), hero));
        }
        return rewardShow;
    }

    public GameResult<Byte> off(Role role, Hero hero, byte pos, boolean updatePower) {
        GameResult<Byte> r = new GameResult<>();
        Spice spice = getPosItems(pos);
        if (spice == null) {
            return r.fail("星格不存在");
        }
        spice.onHeroUid = null;
        spiceMap.remove(pos);
        r.data = pos;
        if (updatePower) {
            hero.getRole().getBase().updatePower();
            publishEvent(role, new HeroPowerChangeEvent(hero.getRole(), hero));
        }
        return r;
    }

    public GameResult<Byte> off(Role role, Hero hero, String spiceUid, boolean updatePower) {
        GameResult<Byte> r = new GameResult<>();
        Map.Entry<Byte, String> spiceEntry = getUidEntry(spiceUid);
        if (spiceEntry == null) {
            return r.fail("星格不存在");
        }
        return off(role, hero, spiceEntry.getKey(), updatePower);
    }

    public GameResult<Byte> on(PlayBuildContext ctx, Hero hero, byte pos, Spice e) {
        GameResult<Byte> r = new GameResult<>();
        if (e == null || e.num <= 0) {
            return r.fail("星格不存在");
        }
        GameResult<Void> checkRes = preCheckOn(ctx, pos, e);
        if (!checkRes.ok()) {
            return r.fail(checkRes);
        }
        if (e.onHeroUid != null) {
            return r.fail("无法装备此星格");
        }
        e.onHeroUid = hero.uid;
        Spice pre = getPosItems(pos);
        if (pre != null) {
            pre.onHeroUid = null;
            role.sendNow(new SpiceUpdateResp(pre));
        }
        spiceMap.put(pos, e.uid);
        return r;
    }

    public Spice getPosItems(byte pos) {
        String spiceUid = spiceMap.get(pos);
        if (role != null && StringUtils.isNotBlank(spiceUid)) {
            return role.getBag().spice.getItem(spiceUid);
        }
        return null;
    }

    private Map.Entry<Byte, String> getUidEntry(String uid) {
        return spiceMap.entrySet().stream().filter(e -> StringUtils.equals(uid, e.getValue())).findAny().orElse(null);
    }

    public void recheck() {
        for (String spiceUid : spiceMap.values()) {
            Spice spice = role.getBag().spice.getItem(spiceUid);
            if (spice != null) {
                spice.onHeroUid = this.owner.uid;
                role.sendNow(new SpiceUpdateResp(spice));
            }
        }
    }
}
